package com.ylg.spring.core;

import com.ylg.spring.annotation.Component;
import com.ylg.spring.annotation.ComponentScan;
import com.ylg.spring.annotation.Resource;
import com.ylg.spring.annotation.Value;

import java.io.File;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class DefaultBeanFactory implements BeanFactory {

    /**
     * 单例Bean 属性完全赋值
     */
    private Map<String, Object> singleObjectBeanMap = new ConcurrentHashMap<>(256);
    /**
     * 提前暴漏的Bean对象 解决循环依赖
     */
    private Map<String, Object> objectBeanMap = new ConcurrentHashMap<>(256);

    private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>(256);


    @Override
    public Map<String, Object> getSingleObjectBeanMap() {
        return singleObjectBeanMap;
    }

    /**
     * 注册Bean定义
     * @param configs
     */
    @Override
    public void registryBeanDefinition(Class[] configs) {

        for (Class config : configs) {

            String beanName = config.getSimpleName().toLowerCase().charAt(0) + config.getSimpleName().substring(1);
            // 注册配置类
            registryBean(beanName, new BeanDefinition(beanName, config));

            if(config.isAnnotationPresent(ComponentScan.class)) {

                ComponentScan componentScan = (ComponentScan) config.getDeclaredAnnotation(ComponentScan.class);
                String[] backPackages = componentScan.backPackages();
                for(String backPackage : backPackages) {
                    componentScan(backPackage);
                }
            }

        }

    }


    /**
     * 扫描包下的类是否含有特定的注解
     * @param backPackage
     */
    private void componentScan(String backPackage) {

        try {

            String classpathFile = backPackage.replaceAll("\\.", "/");
            String path = ClassLoader.getSystemClassLoader().getResource(classpathFile).getPath();
            File file = new File(path);

            // 获取这个路径下所有的文件
            File[] files = file.listFiles();
            for (File classFile : files) {
                if(classFile.isDirectory()) {
                    // 为文件夹 继续递归扫描
                    componentScan(backPackage + "." + classFile.getName());
                } else {
                    // 为文件 判断是否以class结尾
                    if(! classFile.getName() .endsWith(".class")) {
                        continue;
                    }
                    // 以class结尾
                    // 获取它的class对象
                    Class<?> beanClass = Class.forName(backPackage + "." + (classFile.getName().replaceAll(".class", "")));
                    // 判断是否是我们需要的bean
                    if(beanClass.isAnnotationPresent(Component.class)) {
                        Component component = (Component) beanClass.getDeclaredAnnotation(Component.class);
                        String value = component.value();
                        if("".equals(value)) {
                            // 为"" ,我们为它赋默认值
                            value = beanClass.getSimpleName().toLowerCase().charAt(0) + beanClass.getSimpleName().substring(1);
                        }
                        registryBean(value, new BeanDefinition(value, beanClass));
                    }
                }
            }
        } catch (Exception e) {

        }
    }

    private void registryBean(String id, BeanDefinition beanDefinition) {

        beanDefinitionMap.put(id, beanDefinition);

    }

    /**
     * 刷新容器 创建bean对象
     */
    @Override
    public void refreshBeanMap() {

        // TODO bean的生命周期第一步 实例化对象
        // 遍历所有的bean定义 为其创建对象
        for (String beanName : beanDefinitionMap.keySet()) {
            try {
                BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
                Class beanClass = beanDefinition.getBeanClass();
                // 先不给各个对象的属性赋值，先为其创建实例 提前暴漏对象
                Object bean = beanClass.getDeclaredConstructor().newInstance();
                objectBeanMap.put(beanName, bean);
            } catch (Exception e) {
                e.printStackTrace();
            }

        }

        // TODO bean的生命周期第二步 为属性赋值
        for(String beanName : beanDefinitionMap.keySet()) {

            Object singleBean = getSingleBean(beanName);
            if(singleBean == null) {
                // 没有找到其对象
            }

            // 为属性赋值
            Class beanClass = beanDefinitionMap.get(beanName).getBeanClass();
            // 获取到这个类上所有的属性 判断属性上是否有其特定的注解 如果有 则为属性赋值
            for (Field field : beanClass.getDeclaredFields()) {
                try {
                    if(field.isAnnotationPresent(Resource.class)) {
                        // 要赋值的参数类型为引用类型
                        // 获取注解的属性名，如果为""说明使用我们的字段名为其自动注入，否则为注解的属性值
                        Resource resource = (Resource) field.getDeclaredAnnotation(Resource.class);
                        String value = resource.value();
                        if("".equals(value)) {
                            // 获取到字段名称 到我们的容器中去查找 为其赋值
                            value = field.getName();
                        }

                        // 开始赋值
                        Object filedBean = getSingleBean(value);
                        field.setAccessible(true);
                        field.set(singleBean, filedBean);

                    } else if (field.isAnnotationPresent(Value.class)) {
                        // 要赋值的参数类型为基本类型
                        // 获取这个字段上的value注解的属性值
                        Value value = field.getDeclaredAnnotation(Value.class);
                        String propertyValue = value.value();
                        Object val = null;
                        // 判断属性为什么类型，然后赋予什么类型
                        String typeName = field.getType().getSimpleName();
                        switch (typeName) {
                            case "Byte" :
                            case "byte" : val = Byte.parseByte(propertyValue); break;
                            case "Short" :
                            case "short" : val = Short.parseShort(propertyValue); break;
                            case "Integer" :
                            case "int" : val = Integer.parseInt(propertyValue); break;
                            case "Long" :
                            case "long" : val = Long.parseLong(propertyValue); break;
                            case "Float" :
                            case "float" : val = Float.parseFloat(propertyValue); break;
                            case "Double" :
                            case "double" : val = Double.parseDouble(propertyValue); break;
                            case "Boolean" :
                            case "boolean" : val = Boolean.parseBoolean(propertyValue); break;
                            case "Character" :
                            case "char" : val =propertyValue.charAt(0); break;
                        }
                        field.setAccessible(true);
                        field.set(singleBean, val);
                    }
                    // 没有需要为其赋值的属性
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            // 加入容器缓存
            singleObjectBeanMap.put(beanName, singleBean);
        }

        // TODO bean的生命周期第三步 初始化Bean
        // TODO bean的生命周期第四步 使用Bean
        // TODO bean的生命周期第五步 销毁Bean

    }


    /**
     * 通过beanName获取对象
     * @param beanName
     * @return
     */
    public Object getSingleBean(String beanName) {

        Object singleBean = singleObjectBeanMap.get(beanName);
        if(singleBean != null) {
            return singleBean;
        }

        Object bean = objectBeanMap.get(beanName);
        if(bean != null) {
//            objectBeanMap.remove(beanName);
            return bean;
        }

        return null;
    }
}
